/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "MudMobile.h"
#include "CmdVisitor.h"
#include "TaskQueue.h"
#include "Global.h"
#include "MudCorpse.h"
#include "MudItem.h"
#include "MudObjectTask.h"
#include "Room.h"
#include "Utils.h"
#include "config.h"
#include "Logger.h"

using namespace Chronos;
using namespace std;

MudMobile::MudMobile(const std::string& name_, const std::string& descr_, int maxHealth_, int speed_, int maxDamage_, int hitChance_)
    : MudObject(name_, descr_)
    , inCombat(false)
    , combatTarget(0)
{
    stats.set(Stats::maxHealth, maxHealth_);
    stats.set(Stats::speed, speed_);
    stats.set(Stats::maxDamage, maxDamage_);
    stats.set(Stats::hitChance, hitChance_);
}


MudMobile::MudMobile(const string& name_, const string& descr_, const Stats& stats_)
    : MudObject(name_, descr_)
    , stats(stats_)
    , inCombat(false)
    , combatTarget(0)
{}


MudMobile::MudMobile(const MudMobile& rhs)
    : MudObject(rhs)
    , MudObjectListener()
    , stats(rhs.stats)
    , inCombat(false)
    , combatTarget(0)
{}


MudMobile::~MudMobile() {
    if (combatTarget != 0) combatTarget->removeListener(*this);
}


VISITOR_ACCEPT(MudMobile)


bool MudMobile::handleObjectEvent(MudObject& object, MudObjectEvent event) {
	if (combatTarget == &object) {
	    if (!inCombat) return true;
	    switch(event) {
	    case OBJECT_DESTRUCTION:
	    case MUDMOBILE_DEATH:
	        combatTarget = 0;
	        inCombat = false;
	        return false;
	    default:
    	    break;
	    }
	}
    return true;
}


void MudMobile::write(const std::string&) {
    LOG(ERROR, "Talking to an NPC");
}


void MudMobile::addTarget(MudMobile& target) {
    if (!inCombat) {
        inCombat = true;
        combatTarget = &target;
        combatTarget->addListener(*this);
        Global<TaskQueue>()->addTask(new MudObjectFuncTask<MudMobile>(*this, &MudMobile::doCombat), 1);
        generateEvent(MUDMOBILE_START_COMBAT);
    }
}


void MudMobile::die(const string& cause) {
    if (inCombat) {
        inCombat = false;
        combatTarget->removeListener(*this);
        combatTarget = 0;
    }
    stats.setHealth(0);
    generateEvent(MUDMOBILE_DEATH);
	createCorpse(cause);
}


void MudMobile::createCorpse(const std::string& cause) {
	string corpseName = "corpse of " + name;
	MudCorpse* corpse = new MudCorpse(corpseName, "It's dead. ("+ cause + ")");
	corpse->addItem(new MudItem(0, "loot", "a piece of loot.", 1));
	room->addObject(corpse);
	Global<TaskQueue>()->addTask(new MudObjectFuncTask<MudCorpse>(*corpse, &MudCorpse::vanish), seconds(Config::CORPSE_VANISH_TIME));
}


bool MudMobile::isInCombat() const { return inCombat; }

const Stats& MudMobile::getStats() const { return stats; }

int MudMobile::getHealth() const { return stats.getHealth(); }

int MudMobile::getMaxHealth() const { return stats[Stats::maxHealth]; }

void MudMobile::heal(unsigned int hp) { stats.modifyHealth(hp); }

